package com.cencat.common.utils;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.function.Supplier;

/**
 * PageHelper分页工具类
 * 提供基于PageHelper的分页查询功能
 * 
 * @author cencat
 * @since 2024-01-01
 */
public class PageHelperUtils {
    
    private static final Logger log = LoggerFactory.getLogger(PageHelperUtils.class);

    /**
     * 私有构造函数，防止实例化
     */
    private PageHelperUtils() {
        throw new UnsupportedOperationException("Utility class cannot be instantiated");
    }

    /**
     * 默认页码
     */
    public static final int DEFAULT_PAGE_NUM = 1;

    /**
     * 默认每页大小
     */
    public static final int DEFAULT_PAGE_SIZE = 10;

    /**
     * 最大每页大小
     */
    public static final int MAX_PAGE_SIZE = 1000;

    /**
     * 开始分页
     * 
     * @param pageNum 页码
     * @param pageSize 每页大小
     * @return Page对象
     */
    public static <T> Page<T> startPage(Integer pageNum, Integer pageSize) {
        return startPage(pageNum, pageSize, true);
    }

    /**
     * 开始分页
     * 
     * @param pageNum 页码
     * @param pageSize 每页大小
     * @param count 是否进行count查询
     * @return Page对象
     */
    public static <T> Page<T> startPage(Integer pageNum, Integer pageSize, Boolean count) {
        return startPage(pageNum, pageSize, count, null, null);
    }

    /**
     * 开始分页
     * 
     * @param pageNum 页码
     * @param pageSize 每页大小
     * @param orderBy 排序字段
     * @return Page对象
     */
    public static <T> Page<T> startPage(Integer pageNum, Integer pageSize, String orderBy) {
        return startPage(pageNum, pageSize, true, null, orderBy);
    }

    /**
     * 开始分页
     * 
     * @param pageNum 页码
     * @param pageSize 每页大小
     * @param count 是否进行count查询
     * @param reasonable 分页合理化,null时用默认配置
     * @param orderBy 排序字段
     * @return Page对象
     */
    public static <T> Page<T> startPage(Integer pageNum, Integer pageSize, Boolean count, Boolean reasonable, String orderBy) {
        // 参数校验和默认值设置
        pageNum = pageNum == null || pageNum < 1 ? DEFAULT_PAGE_NUM : pageNum;
        pageSize = pageSize == null || pageSize < 1 ? DEFAULT_PAGE_SIZE : pageSize;
        pageSize = pageSize > MAX_PAGE_SIZE ? MAX_PAGE_SIZE : pageSize;
        
        Page<T> page = PageHelper.startPage(pageNum, pageSize, count);
        
        if (reasonable != null) {
            PageHelper.orderBy(orderBy);
        }
        
        if (CencatStringUtils.isNotBlank(orderBy)) {
            PageHelper.orderBy(orderBy);
        }
        
        return page;
    }

    /**
     * 执行分页查询
     * 
     * @param pageNum 页码
     * @param pageSize 每页大小
     * @param querySupplier 查询方法
     * @param <T> 数据类型
     * @return 分页结果
     */
    public static <T> PageResult<T> doSelectPage(Integer pageNum, Integer pageSize, Supplier<List<T>> querySupplier) {
        return doSelectPage(pageNum, pageSize, true, querySupplier);
    }

    /**
     * 执行分页查询
     * 
     * @param pageNum 页码
     * @param pageSize 每页大小
     * @param count 是否进行count查询
     * @param querySupplier 查询方法
     * @param <T> 数据类型
     * @return 分页结果
     */
    public static <T> PageResult<T> doSelectPage(Integer pageNum, Integer pageSize, Boolean count, Supplier<List<T>> querySupplier) {
        return doSelectPage(pageNum, pageSize, count, null, querySupplier);
    }

    /**
     * 执行分页查询
     * 
     * @param pageNum 页码
     * @param pageSize 每页大小
     * @param orderBy 排序字段
     * @param querySupplier 查询方法
     * @param <T> 数据类型
     * @return 分页结果
     */
    public static <T> PageResult<T> doSelectPage(Integer pageNum, Integer pageSize, String orderBy, Supplier<List<T>> querySupplier) {
        return doSelectPage(pageNum, pageSize, true, orderBy, querySupplier);
    }

    /**
     * 执行分页查询
     * 
     * @param pageNum 页码
     * @param pageSize 每页大小
     * @param count 是否进行count查询
     * @param orderBy 排序字段
     * @param querySupplier 查询方法
     * @param <T> 数据类型
     * @return 分页结果
     */
    public static <T> PageResult<T> doSelectPage(Integer pageNum, Integer pageSize, Boolean count, String orderBy, Supplier<List<T>> querySupplier) {
        try {
            // 开始分页
            startPage(pageNum, pageSize, count, null, orderBy);
            
            // 执行查询
            List<T> list = querySupplier.get();
            
            // 获取分页信息
            PageInfo<T> pageInfo = new PageInfo<>(list);
            
            // 转换为统一的分页结果
            return convertToPageResult(pageInfo);
            
        } catch (Exception e) {
            log.error("分页查询异常: {}", e.getMessage(), e);
            // 返回空的分页结果
            return PageResult.<T>builder()
                    .pageNum(pageNum != null ? pageNum : DEFAULT_PAGE_NUM)
                    .pageSize(pageSize != null ? pageSize : DEFAULT_PAGE_SIZE)
                    .total(0L)
                    .pages(0)
                    .list(List.of())
                    .build();
        } finally {
            // 清理ThreadLocal
            PageHelper.clearPage();
        }
    }

    /**
     * 转换PageInfo为PageResult
     * 
     * @param pageInfo PageInfo对象
     * @param <T> 数据类型
     * @return PageResult对象
     */
    public static <T> PageResult<T> convertToPageResult(PageInfo<T> pageInfo) {
        return PageResult.<T>builder()
                .pageNum(pageInfo.getPageNum())
                .pageSize(pageInfo.getPageSize())
                .total(pageInfo.getTotal())
                .pages(pageInfo.getPages())
                .list(pageInfo.getList())
                .isFirstPage(pageInfo.isIsFirstPage())
                .isLastPage(pageInfo.isIsLastPage())
                .hasPreviousPage(pageInfo.isHasPreviousPage())
                .hasNextPage(pageInfo.isHasNextPage())
                .navigatePages(pageInfo.getNavigatePages())
                .navigatePageNums(pageInfo.getNavigatepageNums())
                .build();
    }

    /**
     * 分页结果封装类
     * 
     * @param <T> 数据类型
     */
    @Data
    public static class PageResult<T> {
        
        /**
         * 当前页码
         */
        private Integer pageNum;
        
        /**
         * 每页大小
         */
        private Integer pageSize;
        
        /**
         * 总记录数
         */
        private Long total;
        
        /**
         * 总页数
         */
        private Integer pages;
        
        /**
         * 当前页数据
         */
        private List<T> list;
        
        /**
         * 是否为第一页
         */
        private Boolean isFirstPage;
        
        /**
         * 是否为最后一页
         */
        private Boolean isLastPage;
        
        /**
         * 是否有前一页
         */
        private Boolean hasPreviousPage;
        
        /**
         * 是否有下一页
         */
        private Boolean hasNextPage;
        
        /**
         * 导航页码数
         */
        private Integer navigatePages;
        
        /**
         * 所有导航页号
         */
        private int[] navigatePageNums;
        
        /**
         * 创建Builder实例
         * @param <T> 数据类型
         * @return Builder实例
         */
        public static <T> Builder<T> builder() {
            return new Builder<>();
        }
        
        /**
         * PageResult构建器
         * @param <T> 数据类型
         */
        public static class Builder<T> {
            private Integer pageNum;
            private Integer pageSize;
            private Long total;
            private Integer pages;
            private List<T> list;
            private Boolean isFirstPage;
            private Boolean isLastPage;
            private Boolean hasPreviousPage;
            private Boolean hasNextPage;
            private Integer navigatePages;
            private int[] navigatePageNums;
            
            public Builder<T> pageNum(Integer pageNum) {
                this.pageNum = pageNum;
                return this;
            }
            
            public Builder<T> pageSize(Integer pageSize) {
                this.pageSize = pageSize;
                return this;
            }
            
            public Builder<T> total(Long total) {
                this.total = total;
                return this;
            }
            
            public Builder<T> pages(Integer pages) {
                this.pages = pages;
                return this;
            }
            
            public Builder<T> list(List<T> list) {
                this.list = list;
                return this;
            }
            
            public Builder<T> isFirstPage(Boolean isFirstPage) {
                this.isFirstPage = isFirstPage;
                return this;
            }
            
            public Builder<T> isLastPage(Boolean isLastPage) {
                this.isLastPage = isLastPage;
                return this;
            }
            
            public Builder<T> hasPreviousPage(Boolean hasPreviousPage) {
                this.hasPreviousPage = hasPreviousPage;
                return this;
            }
            
            public Builder<T> hasNextPage(Boolean hasNextPage) {
                this.hasNextPage = hasNextPage;
                return this;
            }
            
            public Builder<T> navigatePages(Integer navigatePages) {
                this.navigatePages = navigatePages;
                return this;
            }
            
            public Builder<T> navigatePageNums(int[] navigatePageNums) {
                this.navigatePageNums = navigatePageNums;
                return this;
            }
            
            public PageResult<T> build() {
                PageResult<T> result = new PageResult<>();
                result.pageNum = this.pageNum;
                result.pageSize = this.pageSize;
                result.total = this.total;
                result.pages = this.pages;
                result.list = this.list;
                result.isFirstPage = this.isFirstPage;
                result.isLastPage = this.isLastPage;
                result.hasPreviousPage = this.hasPreviousPage;
                result.hasNextPage = this.hasNextPage;
                result.navigatePages = this.navigatePages;
                result.navigatePageNums = this.navigatePageNums;
                return result;
            }
        }
    }

    /**
     * 分页查询参数
     */
    @Data
    public static class PageQuery {
        /**
         * 当前页码
         */
        private Integer pageNum = DEFAULT_PAGE_NUM;

        /**
         * 每页大小
         */
        private Integer pageSize = DEFAULT_PAGE_SIZE;

        /**
         * 排序字段
         */
        private String orderBy;

        /**
         * 是否进行count查询
         */
        private Boolean count = true;

        /**
         * 分页合理化
         */
        private Boolean reasonable = true;
        
        /**
         * 执行分页查询
         * 
         * @param querySupplier 查询方法
         * @param <T> 数据类型
         * @return 分页结果
         */
        public <T> PageResult<T> doSelect(Supplier<List<T>> querySupplier) {
            return PageHelperUtils.doSelectPage(pageNum, pageSize, count, orderBy, querySupplier);
        }
    }
}